<html>
<head>
	<title>
		Google Analytics Event Tracking Example: Embedded YouTube Videos
	</title>
	<script type="text/javascript">
		var _gaq = _gaq || [];
		_gaq.push(['_setAccount', 'UA-XXXXXXXX-X']);
		_gaq.push(['_trackPageview']);

		(function() {
			var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
			ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
			var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
		})();
	</script>
</head>
<body>

<script src="http://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js" type="text/javascript">
</script>
  
<br />
<div align="center">
<div align="center" id="ytapiplayer">
<iframe frameborder="0" height="198" id="video-container" src="https://www.youtube.com/embed/rdQNr2sV4PI" width="332"></iframe>
</div>
<div style="text-align: center;">
<br /></div>
<div id="videoProgress" style="text-align: center;">
Watch here for video progress updates.
</div>
</div>
<br />
<div>
<u>Notes:</u><br />
<ul>
<li>Video ID - The video can be tracked by YouTube ID (as in the above 
example), or with a "friendly" name such as the video's actual title 
("Beware of the Phog").&nbsp; Note that both options are to be hard-coded 
into the implementation. &nbsp;This setting can be easily modified.</li>
<li>Restart - If a visitor restarts the video after it has been viewed 100% of the way through, all milestones are tracked a second (third...) time.&nbsp; This setting can be easily modified.</li>
</ul>
<u>Video progress is tracked at the following milestones</u>:
<br />
<ul>
<li>Play - A "play" event is incremented only the first time "play" occurs.</li>
<li>Pause - Every "pause" event is captured if it occurs before 92% of the video has been viewed.  This limit is in place because the YouTube player fires a "pause" event immediately before the final "complete" event.  The intent is to avoid tracking this automated "pause."</li>
<li>25% Progress - When the video reaches 25% of the total video time, an event is incremented.</li>
<li>50% Progress - When the video reaches 50% of the total video time, an event is incremented.</li>
<li>75% Progress - When the video reaches 75% of the total video time, an event is incremented.</li>
<li>Complete - When the video reaches 100% completion, a "complete" event is incremented.</li>
</ul>
<div>
<u><br /></u><br />
<u>Reporting Options</u>:</div>
</div>
<div>
<br /></div>
<div>
The above implementation uses Google Analytics Events to track video progress. &nbsp;Data is sent to GA as follows:</div>
<div>
<ul>
<li>Event Category: &nbsp;"YouTube" is passed in the above example. &nbsp;This allows for the implementation of similar tracking with videos that are hosted by other providers.</li>
<li>Event Label: &nbsp;Video ID or Name</li>
<li>Event Action: &nbsp;Video progress events (Play, Pause, 25%, 50%, 75%, Complete)</li>
</ul>
<div>
Reporting Example #1 - Google Analytics Interface</div>
</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-NZFC9tu0lG8/T6NLbH6cF3I/AAAAAAAAu0U/12MN596LDMs/s1600/google-analytics-youtube-tracking-events.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="123" src="http://3.bp.blogspot.com/-NZFC9tu0lG8/T6NLbH6cF3I/AAAAAAAAu0U/12MN596LDMs/s400/google-analytics-youtube-tracking-events.png" width="400" /></a></div>
<div>
<br /></div>
<div>
Reporting Example #2 - Excel Pivot Table</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-T_MXvh6evRI/T6NLauS-RTI/AAAAAAAAu0M/LZvioDq-iHg/s1600/google-analytics-events-pivot-table.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="48" src="http://1.bp.blogspot.com/-T_MXvh6evRI/T6NLauS-RTI/AAAAAAAAu0M/LZvioDq-iHg/s400/google-analytics-events-pivot-table.png" width="400" /></a></div>
<div>
<br /></div>
<div>
&gt;&gt;&gt; &nbsp;<a href="http://bcj19.googlecode.com/svn/trunk/ytVideoTrackingExample.html" rel="nofollow" target="_blank">GET THE CODE!</a> &nbsp;&lt;&lt;&lt;</div>
<script type="text/javascript">
 if ("undefined"==typeof($tG)) {$tG={};} //define $tG object 
 /*
  * $tG.videoTrackReset - reset variables in case visitor restarts video
  */
 $tG.videoTrackReset=function(){
  $tG.isTracked=false;
  $tG.is25=$tG.is50=$tG.is75=false;
  $tG.isReset=true; //reset to false in onytplayerStateChange()
 }
 
 /*
  * $tG.videoTrackYouTube - identify which analytics information to send, if appropriate
  */
 $tG.videoTrackYouTube=function(pv_videoId,pv_videoEvent){
  var returnVal="";
  var sendCall=false;
  switch(pv_videoEvent) {
   case "play":
    if(!$tG.isTracked) { //only track the initial play event
     returnVal="video play";
     $tG.isTracked=true;
     sendCall=true;
    }
    break;
   case "pause":
    returnVal="video paused";
    sendCall=true; //enable this line to send event call
    break;
   case "progress25":
    if(!$tG.is25) { returnVal="video 25%"; }
    sendCall=true; //enable this line to send event call
    break;
   case "progress50":
    if(!$tG.is50) { returnVal="video 50%"; }
    sendCall=true; //enable this line to send event call
    break;
   case "progress75":
    if(!$tG.is75) { returnVal="video 75%"; }
    sendCall=true; //enable this line to send event call
    break;
   case "complete":
    if(!$tG.isComplete) { returnVal="video complete"; }
    sendCall=true; //enable this line to send event call
    break;
  }

  if(sendCall) { //only send calls with above data if sendCall=true (set to false, by default);
   if(returnVal) {
    //category,action,label,value
    //youtube | event | id/name
    _gaq.push(['_trackEvent','YouTube',returnVal,pv_videoId]);
 document.getElementById("videoProgress").innerHTML="Video ID: <a href='http://www.youtube.com/watch?v="+pv_videoId+"' target='_blank'>"+pv_videoId+"</a> | Progress: <b>"+returnVal+"</b>";
   }
  }
  if(returnVal=="video complete") {
   $tG.videoTrackReset(); //if video is complete, reset variables to enable tracking on restart
  }
 } 
 
/********** YouTube video embed settings **********/
 $tG.videoId="rdQNr2sV4PI";//specify 11 character youtube video id
 $tG.videoTitle="";//specify the video title to use in GA reports. if not provided, $tG.videoId is used
 ($tG.videoTitle) ? $tG.videoTitleOrId=$tG.videoTitle : $tG.videoTitleOrId=$tG.videoId;
 
  var videoHeight="198";
 var videoWidth="332";
  var videoParams = { allowScriptAccess: "always",allowFullScreen: "true" };
  var videoAtts = { id: "myytplayer" }; //attributes
 var videoDisplayDiv = "ytapiplayer"; //id of div to display the video in
 
 //embed the video
 swfobject.embedSWF("http://www.youtube.com/v/"+$tG.videoId+"?enablejsapi=1&playerapiid=ytplayer&version=3",
                       videoDisplayDiv, videoWidth, videoHeight, "8", null, null, videoParams, videoAtts);
/********** End | YouTube video embed settings **********/ 

 /*
  * onYouTubePlayerReady - when player has loaded, grab the object and add event listeners
  */
 function onYouTubePlayerReady(playerId) {
  ytplayer = document.getElementById("myytplayer");
  ytplayer.addEventListener("onStateChange", "onytplayerStateChange");
  setInterval(updateytplayerInfo, 500); //check video status every 500ms
  
  //define $tG variables
  $tG.videoDuration=ytplayer.getDuration(); //get total video duration (in seconds)
  $tG.videoUrl=ytplayer.getVideoUrl(); //get url to video on youtube.com
 }

 /*
  * onytplayerStateChange - check for state changes:
  * - -1= Not started
  * - 0 = Ended
  * - 1 = Playing
  * - 2 = Paused
  * - 3 = Buffering
  * - 5 = Cued
  */
 function onytplayerStateChange(newState) {
  var videoState;
  switch(newState) {
   case -1:videoState="not started";break;
   case 0: videoState="complete";break;
   case 1: 
    videoState="play";
    $tG.isReset=false; //req'd to enable tracking re-started videos
    break;
   case 2: 
    ($tG.timePercentComplete<92) ? videoState="pause" : videoState=newState; //prevent "pause" call at video complete
    break;
   case 3: videoState="buffer";break;
   case 5: videoState="cued";break;
   default:videoState=newState;
  }
  if(videoState) { $tG.videoTrackYouTube($tG.videoTitleOrId,videoState); } //sends analytics call, if necessary
 }

 /*
  * updateytplayerInfo - watch for changes in player during playback,
  *  primary use is to identify % of video viewed
  */
 function updateytplayerInfo(){
  var timePosition=ytplayer.getCurrentTime(); //get position in video (in seconds)
  var timeDuration=$tG.videoDuration; //get total duration of video (in seconds)
  
  var timePercentComplete=(timePosition/timeDuration)*100; //calculate percent complete
  timePercentComplete=Math.round(timePercentComplete); //round to a whole number
  if($tG.isReset) { timePercentComplete=0; } //don't allow progress calls until video is restarted
  $tG.timePercentComplete=timePercentComplete;
    
  if(!$tG.is25) { //has video reached 25% complete?
   if(timePercentComplete>24) { $tG.videoTrackYouTube($tG.videoTitleOrId,'progress25'); $tG.is25=true; }
  }
  if(!$tG.is50) { //has video reached 50% complete?
   if(timePercentComplete>49) { $tG.videoTrackYouTube($tG.videoTitleOrId,'progress50'); $tG.is50=true; }
  }
  if(!$tG.is75) { //has video reached 75% complete?
   if(timePercentComplete>74) { $tG.videoTrackYouTube($tG.videoTitleOrId,'progress75'); $tG.is75=true; }
  }
 }
</script>

</body>
</html>
